package com.data.mall.service.impl;

import com.data.mall.common.KafkaTrackingDTO;
import com.data.mall.domain.User;
import com.data.mall.domain.UserPassword;
import com.data.mall.etl.domain.enums.Event;
import com.data.mall.etl.domain.enums.Params;
import com.data.mall.exception.BusinessException;
import com.data.mall.exception.ResponseCodeEnum;
import com.data.mall.kafka.KafkaProduceService;
import com.data.mall.repositry.UserPasswordRepository;
import com.data.mall.repositry.UserRepository;
import com.data.mall.service.UserService;
import com.data.mall.service.dto.UserDTO;
import com.data.mall.utils.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @author shixukai
 * @Package com.data.mall.service.impl
 * @Description: TODO
 * @date 2021/4/6
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserPasswordRepository userPasswordRepository;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    KafkaProduceService kafkaProduceService;

    @Override
    public UserDTO getUserById(Long id) {
        //获取用户
        Optional<User> optional = userRepository.findById(id);
        if (optional.isPresent()) {

            User user = optional.get();
            UserPassword userPassword = userPasswordRepository.findByUserId(id);

            return convertFromDataObject(user, userPassword);
        }
        return null;
    }

    @Override
    public UserDTO getUserByIdInCache(Long id) {
        UserDTO dto = (UserDTO) redisTemplate.opsForValue().get("user_validate_" + id);
        if (dto == null) {
            dto = this.getUserById(id);
            redisTemplate.opsForValue().set("user_validate_" + id, dto);
            redisTemplate.expire("user_validate_" + id, 10, TimeUnit.MINUTES);
        }
        return null;
    }

    @Override
    @Transactional
    public void register(UserDTO dto) throws BusinessException {
        if (dto == null) {
            //抛出错误
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR);
        }
        //做参数校验

        User user = convertFromDTO(dto);
        try {
            userRepository.saveAndFlush(user);
        } catch (DuplicateKeyException ex) {
            //需要在telphone上加唯一索引
            //这里捕获到手机号重复异常并进行抛出
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR, "手机号重复");
        }

        dto.setId(user.getId());

        UserPassword userPassword = convertPasswordFromDTO(dto);
        // 埋点
        KafkaTrackingDTO kafkaTrackingDTO = KafkaTrackingDTO.builder()
                .event(Event.USER_REG)
                .param(Params.USER, JSON.toJSONString(dto))
                .build();
        kafkaProduceService.sendTrackingMessage(kafkaTrackingDTO);
        userPasswordRepository.save(userPassword);

    }

    @Override
    public UserDTO validateLogin(String telphone, String encrptPassword) throws BusinessException {
        //通过手机号获取用户信息
        User user = userRepository.findByTelphone(telphone);
        if (user == null) {
            //抛出错误
        }

        UserPassword userPassword = userPasswordRepository.findByUserId(user.getId());
        UserDTO dto = convertFromDataObject(user, userPassword);

        //比对用户信息内加密的密码是否和传输进来的密码相匹配
        if (!StringUtils.equals(encrptPassword, dto.getEncrptPassword())) {
            //抛出错误
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR, "账号或密码不正确");
        }

        return dto;
    }

    private UserPassword convertPasswordFromDTO(UserDTO dto) {
        if (dto == null) {
            return null;
        }
        UserPassword.UserPasswordBuilder builder = UserPassword.builder();
        builder.userId(dto.getId());
        builder.encrptPassword(dto.getEncrptPassword());
        return builder.build();
    }

    private User convertFromDTO(UserDTO dto) {
        if (dto == null) {
            return null;
        }
        User user = new User();
        BeanUtils.copyProperties(dto, user);
        return user;
    }

    private UserDTO convertFromDataObject(User user, UserPassword userPassword) {
        if (user == null) {
            return null;
        }
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user, userDTO);

        if (userPassword != null) {
            userDTO.setEncrptPassword(userPassword.getEncrptPassword());
        }

        return userDTO;
    }
}
